import type { BoundingBox, GraphicObject, Point } from './GraphicObject';

export class SelectionManager {
  private selectedObjects: Set<GraphicObject> = new Set();
  private listeners: Map<string, Function[]> = new Map();

  /**
   * 选择对象
   */
  select(object: GraphicObject, additive: boolean = false): void {
    if (!additive) {
      this.clearSelection();
    }

    if (!this.selectedObjects.has(object)) {
      this.selectedObjects.add(object);
      this.emit('selectionChanged', {
        selectedObjects: this.getSelectedObjects(),
      });
    }
  }

  /**
   * 取消选择对象
   */
  deselect(object: GraphicObject): void {
    if (this.selectedObjects.has(object)) {
      this.selectedObjects.delete(object);
      this.emit('selectionChanged', {
        selectedObjects: this.getSelectedObjects(),
      });
    }
  }

  /**
   * 清空选择
   */
  clearSelection(): void {
    if (this.selectedObjects.size > 0) {
      this.selectedObjects.clear();
      this.emit('selectionChanged', {
        selectedObjects: this.getSelectedObjects(),
      });
    }
  }

  /**
   * 获取选中的对象
   */
  getSelectedObjects(): GraphicObject[] {
    return Array.from(this.selectedObjects);
  }

  /**
   * 检查对象是否被选中
   */
  isSelected(object: GraphicObject): boolean {
    return this.selectedObjects.has(object);
  }

  /**
   * 框选对象
   */
  selectInRect(rect: BoundingBox, objects: GraphicObject[]): GraphicObject[] {
    const selected: GraphicObject[] = [];

    for (const obj of objects) {
      const bbox = obj.getBoundingBox();

      // 检查边界框是否相交
      if (this.rectIntersects(rect, bbox)) {
        selected.push(obj);
      }
    }

    return selected;
  }

  /**
   * 点选对象
   */
  selectAtPoint(point: Point, objects: GraphicObject[]): GraphicObject | null {
    // 从后往前检查（Z轴顺序）
    for (let i = objects.length - 1; i >= 0; i--) {
      const obj = objects[i];
      if (obj.contains(point)) {
        return obj;
      }
    }
    return null;
  }

  /**
   * 多重点选对象
   */
  selectMultipleAtPoint(
    point: Point,
    objects: GraphicObject[],
  ): GraphicObject[] {
    const selected: GraphicObject[] = [];

    for (const obj of objects) {
      if (obj.contains(point)) {
        selected.push(obj);
      }
    }

    return selected;
  }

  /**
   * 选择所有对象
   */
  selectAll(objects: GraphicObject[]): void {
    this.clearSelection();
    for (const obj of objects) {
      this.selectedObjects.add(obj);
    }
    this.emit('selectionChanged', {
      selectedObjects: this.getSelectedObjects(),
    });
  }

  /**
   * 反选对象
   */
  invertSelection(objects: GraphicObject[]): void {
    for (const obj of objects) {
      if (this.selectedObjects.has(obj)) {
        this.selectedObjects.delete(obj);
      } else {
        this.selectedObjects.add(obj);
      }
    }
    this.emit('selectionChanged', {
      selectedObjects: this.getSelectedObjects(),
    });
  }

  /**
   * 获取选择边界框
   */
  getSelectionBounds(): BoundingBox | null {
    const selected = this.getSelectedObjects();
    if (selected.length === 0) return null;

    let minX = Infinity,
      maxX = -Infinity;
    let minY = Infinity,
      maxY = -Infinity;

    for (const obj of selected) {
      const bbox = obj.getBoundingBox();
      minX = Math.min(minX, bbox.x);
      maxX = Math.max(maxX, bbox.x + bbox.width);
      minY = Math.min(minY, bbox.y);
      maxY = Math.max(maxY, bbox.y + bbox.height);
    }

    return {
      x: minX,
      y: minY,
      width: maxX - minX,
      height: maxY - minY,
    };
  }

  /**
   * 获取选择中心点
   */
  getSelectionCenter(): Point | null {
    const bounds = this.getSelectionBounds();
    if (!bounds) return null;

    return {
      x: bounds.x + bounds.width / 2,
      y: bounds.y + bounds.height / 2,
    };
  }

  /**
   * 事件监听
   */
  on(event: string, callback: Function): void {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, []);
    }
    this.listeners.get(event)!.push(callback);
  }

  /**
   * 移除事件监听
   */
  off(event: string, callback: Function): void {
    const callbacks = this.listeners.get(event);
    if (callbacks) {
      const index = callbacks.indexOf(callback);
      if (index > -1) {
        callbacks.splice(index, 1);
      }
    }
  }

  /**
   * 触发事件
   */
  private emit(event: string, data: any): void {
    const callbacks = this.listeners.get(event);
    if (callbacks) {
      for (const callback of callbacks) {
        callback(data);
      }
    }
  }

  /**
   * 检查两个矩形是否相交
   */
  private rectIntersects(rectA: BoundingBox, rectB: BoundingBox): boolean {
    return (
      rectA.x < rectB.x + rectB.width &&
      rectA.x + rectA.width > rectB.x &&
      rectA.y < rectB.y + rectB.height &&
      rectA.y + rectA.height > rectB.y
    );
  }

  /**
   * 销毁选择管理器
   */
  destroy(): void {
    this.selectedObjects.clear();
    this.listeners.clear();
  }
}

export default SelectionManager;
